// DEPRECATED: alias for componentInstance for backwards compat. /* istanbul ignore next https://github.com/answershuto/learnVue*/ get child(): Component | void { returnthis.componentInstance; } }
// plain options object: turn it into a constructor https://github.com/answershuto/learnVue if (isObject(Ctor)) { Ctor = baseCtor.extend(Ctor) }
// if at this stage it's not a constructor or an async component factory, // reject. /*Github:https://github.com/answershuto*/ /*如果在该阶段Ctor依然不是一个构造函数或者是一个异步组件工厂则直接返回*/ if (typeof Ctor !== 'function') { if (process.env.NODE_ENV !== 'production') { warn(`Invalid Component definition: ${String(Ctor)}`, context) } return }
// async component /*处理异步组件*/ if (isUndef(Ctor.cid)) { Ctor = resolveAsyncComponent(Ctor, baseCtor, context) if (Ctor === undefined) { // return nothing if this is indeed an async component // wait for the callback to trigger parent update. /*如果这是一个异步组件则会不会返回任何东西(undifiened),直接return掉,等待回调函数去触发父组件更新。s*/ return } }
// resolve constructor options in case global mixins are applied after // component constructor creation resolveConstructorOptions(Ctor)
data = data || {}
// transform component v-model data into props & events if (isDef(data.model)) { transformModel(Ctor.options, data) }
// extract listeners, since these needs to be treated as // child component listeners instead of DOM listeners const listeners = data.on // replace with listeners with .native modifier data.on = data.nativeOn
if (isTrue(Ctor.options.abstract)) { // abstract components do not keep anything // other than props & listeners data = {} }
// merge component management hooks onto the placeholder node mergeHooks(data)
// return a placeholder vnode const name = Ctor.options.name || tag const vnode = new VNode( `vue-component-${Ctor.cid}${name ? `-${name}` : ''}`, data, undefined, undefined, undefined, context, { Ctor, propsData, listeners, tag, children } ) return vnode }
createElement 用来创建一个虚拟节点。当 data 上已经绑定ob的时候,代表该对象已经被 Oberver 过了,所以创建一个空节点。tag 不存在的时候同样创建一个空节点。当 tag 不是一个 String 类型的时候代表 tag 是一个组件的构造类,直接用 new VNode 创建。当 tag 是 String 类型的时候,如果是保留标签,则用 new VNode 创建一个 VNode 实例,如果在 vm 的 option 的 components 找得到该 tag,代表这是一个组件,否则统一用 new VNode 创建。
Vue.prototype._update = function (vnode: VNode, hydrating?: boolean) { const vm: Component = this /*如果已经该组件已经挂载过了则代表进入这个步骤是个更新的过程,触发beforeUpdate钩子*/ if (vm._isMounted) { callHook(vm, 'beforeUpdate') } const prevEl = vm.$el const prevVnode = vm._vnode const prevActiveInstance = activeInstance activeInstance = vm vm._vnode = vnode // Vue.prototype.__patch__ is injected in entry points // based on the rendering backend used. /*基于后端渲染Vue.prototype.__patch__被用来作为一个入口*/ if (!prevVnode) { // initial render vm.$el = vm.__patch__( vm.$el, vnode, hydrating, false/* removeOnly */, vm.$options._parentElm, vm.$options._refElm ) } else { // updates vm.$el = vm.__patch__(prevVnode, vnode) } activeInstance = prevActiveInstance // update __vue__ reference /*更新新的实例对象的__vue__*/ if (prevEl) { prevEl.__vue__ = null } if (vm.$el) { vm.$el.__vue__ = vm } // if parent is an HOC, update its $el as well if (vm.$vnode && vm.$parent && vm.$vnode === vm.$parent._vnode) { vm.$parent.$el = vm.$el } // updated hook is called by the scheduler to ensure that children are // updated in a parent's updated hook. }复制代码
/*更新attr*/ functionupdateAttrs(oldVnode: VNodeWithData, vnode: VNodeWithData) { /*如果旧的以及新的VNode节点均没有attr属性,则直接返回*/ if (isUndef(oldVnode.data.attrs) && isUndef(vnode.data.attrs)) { return; } let key, cur, old; /*VNode节点对应的Dom实例*/ const elm = vnode.elm; /*旧VNode节点的attr*/ const oldAttrs = oldVnode.data.attrs || {}; /*新VNode节点的attr*/ let attrs: any = vnode.data.attrs || {}; // clone observed objects, as the user probably wants to mutate it /*如果新的VNode的attr已经有__ob__(代表已经被Observe处理过了), 进行深拷贝*/ if (isDef(attrs.__ob__)) { attrs = vnode.data.attrs = extend({}, attrs); }
/*遍历attr,不一致则替换*/ for (key in attrs) { cur = attrs[key]; old = oldAttrs[key]; if (old !== cur) { setAttr(elm, key, cur); } } // #4391: in IE9, setting type can reset value for input[type=radio] /* istanbul ignore if */ if (isIE9 && attrs.value !== oldAttrs.value) { setAttr(elm, "value", attrs.value); } for (key in oldAttrs) { if (isUndef(attrs[key])) { if (isXlink(key)) { elm.removeAttributeNS(xlinkNS, getXlinkProp(key)); } elseif (!isEnumeratedAttr(key)) { elm.removeAttribute(key); } } } }
/*设置attr*/ functionsetAttr(el: Element, key: string, value: any) { if (isBooleanAttr(key)) { // set attribute for blank value // e.g. <option disabled>Select one</option> if (isFalsyAttrValue(value)) { el.removeAttribute(key); } else { el.setAttribute(key, key); } } elseif (isEnumeratedAttr(key)) { el.setAttribute( key, isFalsyAttrValue(value) || value === "false" ? "false" : "true" ); } elseif (isXlink(key)) { if (isFalsyAttrValue(value)) { el.removeAttributeNS(xlinkNS, getXlinkProp(key)); } else { el.setAttributeNS(xlinkNS, key, value); } } else { if (isFalsyAttrValue(value)) { el.removeAttribute(key); } else { el.setAttribute(key, value); } } }